/*
	This file is part of Vajolet.

    Vajolet is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Vajolet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Vajolet.  If not, see <http://www.gnu.org/licenses/>
*/
//----------------------------------------------------------------------------------
//	INCLUDES
//----------------------------------------------------------------------------------

#include <stdio.h>
#include <signal.h>
#include <iostream>
#include <assert.h>
#include <fcntl.h>

#include "vajolet.h"
#include "command.h"
#include "board.h"
#include "move.h"
#include "data.h"
#include "bitops.h"
#include "hash.h"
#include "movegen.h"

#include "move.h"
#include "timer.h"
#include "search.h"
//----------------------------------------------------------------------------------
//	CODE
//----------------------------------------------------------------------------------
#ifdef _DEBUG_EVAL
Board mir;
#endif

int main(int argc, char *argv[])
{

	checkCpuCapabilities();
	comInit();

	// init useful arrays
	Board::KEY.init();
	dataInit();
	board.initPST();
	board.init();
	board.setMaterialCacheSize(1048576);
	board.setPawnCacheSize(131072);
	Search::initReduction();



#ifdef _DEBUG_EVAL	
	mir.initPST();
	mir.init();
	mir.setMaterialCacheSize(1048576);
	mir.setPawnCacheSize(131072);
	mir.getMirroredBoard(mir,board);

#endif
	
	//autotune();
	//return 0;
	Search::clearHistoryTable();
	while(1){
		command();
	}

	return 0;

}



unsigned long long perft(int depth){
#ifdef _DEBUG_EVAL
	score sorig=board.eval<false>();
	mir.getMirroredBoard(mir,board);
	score smir=mir.eval<false>();
	if(sorig!=smir){
		
		board.display();
		mir.display();
		std::cout<<"errore orig:"<<sorig<<" mir:"<<smir<<std::endl;
		board.gameLine[board.gameLineIndex-1].move.display();
	}
#endif
	Movegen mg(0);
	unsigned long long tot=0;
	if(depth==0){
		return 1;
	}

	Move m;
	if(depth==1){
		//mg.genAll();
		//return mg.quietLastMove+mg.captureLastMove;
		while(mg.getNext(m)){
			board.makeMove(m);
			if(/*!(BITSET[mg.moves[n].from] & KR) || */ !board.isOtherKingAttacked()){
				tot++;
				board.unmakeMove();
			}
			else{
				board.unmakeMove();
				board.display();
				m.display();
				getch();
			}

		}
		return tot;
	}
	while(mg.getNext(m))
	{

		board.makeMove(m);
		//bitMap KR=KINGRAYS[firstOne(board.boards[Board::blackKing-board.nextMove])];
		if(/*!(BITSET[mg.moves[n].from] & KR) || */ !board.isOtherKingAttacked()){
			tot+=perft(depth-1);
			board.unmakeMove();
		}
		else{
			board.unmakeMove();
			//board.display();
			//m.display();
			//getch();
		}




	}
	return tot;
}

unsigned long long fast_perft(int depth){
#ifdef _DEBUG_EVAL
	score sorig=board.eval<false>();
	mir.getMirroredBoard(mir,board);
	score smir=mir.eval<false>();
	if(sorig!=smir){

		board.display();
		mir.display();
		std::cout<<"errore orig:"<<sorig<<" mir:"<<smir<<std::endl;
		board.gameLine[board.gameLineIndex-1].move.display();
	}
#endif
	Movegen mg(0);
	unsigned long long tot=0;
/*	if(depth==0){
		return 1;
	}
*/
	Move m;
	if(depth==1){
		mg.genAll();
		return mg.quietLastMove+mg.captureLastMove;
		while(mg.getNext(m)){
//			board.makeMove(m);
//			if(/*!(BITSET[mg.moves[n].from] & KR) || */ !board.isOtherKingAttacked()){
				tot++;
//				board.unmakeMove();
//			}
//			else{
//				board.unmakeMove();
//				board.display();
//				m.display();
//				getch();
//			}

		}
		return tot;
	}
	while(mg.getNext(m))
	{
	
		board.makeMove(m);
		//bitMap KR=KINGRAYS[firstOne(board.boards[Board::blackKing-board.nextMove])];
//		if(/*!(BITSET[mg.moves[n].from] & KR) || */ !board.isOtherKingAttacked()){
			tot+=perft(depth-1);
			board.unmakeMove();
//		}
//		else{
//			board.unmakeMove();
//			board.display();
//			m.display();
//			getch();
//		}

		


	}
	return tot;
}

unsigned long long divide(int depth){
	Movegen mg(0);
	unsigned long long acc=0;
	unsigned long long tot=0;
	//mg.genMoves();
	Move m;
	while(mg.getNext(m))
	{
		board.makeMove(m);
		

		if (!board.isOtherKingAttacked())
		{
			tot=perft(depth-1);
			acc+=tot;
			board.unmakeMove();
			m.display();
			std::cout<<": "<<tot<<std::endl;
		}else{
			board.unmakeMove();
		}
		
	}
	return acc;
}
